package com.xbq.exceleditor.ui.excel

import android.Manifest
import android.app.Dialog
import android.content.Context
import android.net.Uri
import android.os.Build
import android.os.Bundle
import android.text.TextUtils
import android.util.Base64
import android.util.Log
import android.webkit.ConsoleMessage
import android.webkit.GeolocationPermissions
import android.webkit.JsResult
import android.webkit.PermissionRequest
import android.webkit.RenderProcessGoneDetail
import android.webkit.ValueCallback
import android.webkit.WebChromeClient
import android.webkit.WebView
import android.webkit.WebViewClient
import android.widget.EditText
import androidx.appcompat.app.AlertDialog
import androidx.core.widget.addTextChangedListener
import androidx.fragment.app.Fragment
import androidx.lifecycle.lifecycleScope
import com.blankj.utilcode.util.ActivityUtils
import com.blankj.utilcode.util.FileIOUtils
import com.blankj.utilcode.util.LogUtils
import com.blankj.utilcode.util.ToastUtils
import com.blankj.utilcode.util.UriUtils
import com.gyf.immersionbar.ktx.immersionBar
import com.hjq.permissions.Permission
import com.hjq.permissions.XXPermissions
import com.kongzue.dialogx.dialogs.MessageDialog
import com.kongzue.dialogx.dialogs.WaitDialog
import com.luck.picture.lib.basic.PictureSelector
import com.luck.picture.lib.config.SelectMimeType
import com.luck.picture.lib.config.SelectModeConfig
import com.luck.picture.lib.engine.CompressFileEngine
import com.luck.picture.lib.entity.LocalMedia
import com.luck.picture.lib.interfaces.OnKeyValueResultCallbackListener
import com.luck.picture.lib.interfaces.OnPermissionsInterceptListener
import com.luck.picture.lib.interfaces.OnRequestPermissionListener
import com.luck.picture.lib.interfaces.OnResultCallbackListener
import com.xbq.exceleditor.BuildConfig
import com.xbq.exceleditor.R
import com.xbq.exceleditor.databinding.ActivityExcelBinding
import com.xbq.exceleditor.db.ExcelDatabase
import com.xbq.exceleditor.db.entity.ExcelBean
import com.xbq.exceleditor.utils.GlideEngine
import com.xbq.exceleditor.utils.ensureVipClick
import com.xbq.exceleditor.utils.validateEmpty
import com.xbq.exceleditor.utils.value
import com.xbq.xbqsdk.component.activity.VBActivity
import com.xbq.xbqsdk.util.PathUtils
import com.xbq.xbqsdk.util.click.onDebouncedClick
import com.xbq.xbqsdk.util.ensurePermission
import dagger.hilt.android.AndroidEntryPoint
import kotlinx.coroutines.launch
import top.zibin.luban.Luban
import top.zibin.luban.OnNewCompressListener
import java.io.File
import javax.inject.Inject


/**
 * Author: liaohaiping
 * Time: 2020-10-30
 * Description:
 */
@AndroidEntryPoint
class ExcelActivity : VBActivity<ActivityExcelBinding>() {
    private var mCameraFilePath: String = ""
    private val REQUEST_CODE_FILE_CHOOSER: Int = 100
    lateinit var mRichEditorCallback: RichEditorCallback
    lateinit var mRichEditorAction: RichEditorAction

    //文件选择回调
    //For Android  >= 5.0
    private var chooseFileCallback: ValueCallback<Array<Uri>>? = null


    var excelBean: ExcelBean? = null
    var xlsxPath: String? = null
    @Inject
    lateinit var db: ExcelDatabase
    var dlgProgress: WaitDialog? = null
    @Volatile
    private var shouldFinish = false

    companion object {
        const val EXTRA_EXCEL = "EXTRA_EXCEL"
        const val EXTRA_EXCEL_URL = "EXTRA_EXCEL_URL"

        fun startEdit(doc: ExcelBean) {
            val extra = Bundle().apply {
                putParcelable(EXTRA_EXCEL, doc)
            }
            ActivityUtils.startActivity(extra, ExcelActivity::class.java)
        }

        fun startEdit(xlsxPath: String) {
            val extra = Bundle().apply {
                putString(EXTRA_EXCEL_URL, xlsxPath)
            }
            ActivityUtils.startActivity(extra, ExcelActivity::class.java)
        }
    }

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        immersionBar {
            statusBarView(R.id.statusbar)
        }
        parseData()
        initWebview()
        initView()
        dlgProgress = WaitDialog.show("正在加载，请稍候...")
    }

    override fun onBackPressed() {
        showSaveDialogBefreExit()
    }

    private fun showSaveDialogBefreExit() {
        MessageDialog.show("提示", "是否保存当前文档？")
            .setCancelable(false)
            .setOkButton("保存"){dlg,w->
                dlg.dismiss()
                shouldFinish=true
                saveDoc()
                true
            }
            .setCancelButton("直接退出"){dlg,w->
                dlg.dismiss()
                finish()
                true
            }
    }

    private fun parseData() {
        excelBean = intent.getParcelableExtra(EXTRA_EXCEL)
        xlsxPath = intent.getStringExtra(EXTRA_EXCEL_URL)
    }

    private fun initView() {
        if (excelBean == null) {
            binding.tvTitle.text = getString(R.string.create_document)
        } else {
            binding.tvTitle.text = excelBean!!.title
        }
        binding.menuSave.ensureVipClick(this,"saveExcel") { saveDoc() }
        binding.btnBack.onDebouncedClick {
            showSaveDialogBefreExit()
        }
    }

    private fun initWebview() {
//        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
//            requestPermissions(
//                arrayOf(
//                    Manifest.permission.WRITE_EXTERNAL_STORAGE,
//                    Manifest.permission.READ_EXTERNAL_STORAGE
//                ), 1
//            )
//        }

        WebView.setWebContentsDebuggingEnabled(BuildConfig.DEBUG)
        binding.webview.setWebViewClient(CustomWebviewClient())
        binding.webview.setWebChromeClient(CustomWebChromeClient())
        binding.webview.getSettings().setJavaScriptEnabled(true)
        binding.webview.getSettings().setDomStorageEnabled(true)
        binding.webview.getSettings().setAllowFileAccess(true)
        mRichEditorCallback = RichEditorCallback()
        excelBean?.let {
            val json = FileIOUtils.readFile2String(File(it.path))
            mRichEditorCallback.setData(json)
        }
        xlsxPath?.let {
            val file = File(xlsxPath)
            if (file.exists()) {
                val buffer = FileIOUtils.readFile2BytesByStream(file)
                val encodeToString = Base64.encodeToString(buffer, Base64.CRLF)
                mRichEditorCallback.setFileBase64(encodeToString)
            }
        }

        binding.webview.addJavascriptInterface(mRichEditorCallback, "MRichEditor")
        binding.webview.loadUrl("file:////android_asset/excel/index2.html")

        mRichEditorAction = RichEditorAction(binding.webview)


    }

    override fun onDestroy() {
        binding.webview.destroy()
        super.onDestroy()
    }

    private fun saveDoc() {
        if (excelBean == null) {
            showDocTitleEdit {
                excelBean = ExcelBean().apply {
                    title = it
                    path = PathUtils.newPackageDirFile("excel", ".json").absolutePath
                    xlsxPath = path.replace(".json", ".xlsx")
                }
                lifecycleScope.launch {
                    db.docDao().insert(excelBean!!)
                    mRichEditorAction?.getHtmlAndDocx(
                        mRichEditorCallback,
                        GetHtmlAndDocxListener(excelBean!!)
                    )
                }
            }

        } else {
            mRichEditorAction?.getHtmlAndDocx(
                mRichEditorCallback,
                GetHtmlAndDocxListener(excelBean!!)
            )
        }
    }

    fun showDocTitleEdit(callback: (String) -> Unit) {
        val tv = EditText(this)
        xlsxPath?.let {
            tv.setText(File(it).nameWithoutExtension)
        }
        val dlg = AlertDialog.Builder(this)
            .setView(tv)
            .setTitle(R.string.pls_type_document_title)
            .setCancelable(false)
            .setPositiveButton(R.string.confirm) { dlg, which ->
                if (validateEmpty(tv.value(), R.string.pls_type_document_title)) {
                    dlg.dismiss()
                    callback(tv.value())
                }
            }
            .setNegativeButton(R.string.cancel) { dlg, which -> dlg.dismiss() }
            .show()
        dlg.getButton(Dialog.BUTTON_POSITIVE).isEnabled = tv.text.trim().length > 0
        tv.addTextChangedListener {
            dlg.getButton(Dialog.BUTTON_POSITIVE).isEnabled = it.toString().trim().length > 0
        }

    }

    inner class CustomWebviewClient : WebViewClient() {
        override fun onPageFinished(view: WebView?, url: String?) {
            super.onPageFinished(view, url)
            dlgProgress?.doDismiss()
        }

        override fun onRenderProcessGone(
            view: WebView?,
            detail: RenderProcessGoneDetail?
        ): Boolean {
            return super.onRenderProcessGone(view, detail)
        }

    }

    inner class CustomWebChromeClient : WebChromeClient() {

        override fun onPermissionRequest(request: PermissionRequest?) {
            request?.deny()
        }
        override fun onConsoleMessage(consoleMessage: ConsoleMessage?): Boolean {
            consoleMessage?.let {
                LogUtils.d(
                    "webview",
                    "line:${it.lineNumber()}, sourceId:${it.sourceId()}, message:${it.message()}"
                )
            }
            return true
        }


        override fun onJsAlert(
            view: WebView?,
            url: String?,
            message: String?,
            result: JsResult?
        ): Boolean {
            message?.let {
                AlertDialog.Builder(this@ExcelActivity)
                    .setMessage(it)
                    .show()
            }
            return true
        }


        override fun onShowFileChooser(
            webView: WebView?,
            filePathCallback: ValueCallback<Array<Uri>>?,
            fileChooserParams: FileChooserParams?
        ): Boolean {
            chooseFileCallback = filePathCallback
            showChooser()
            return true
        }

        override fun onGeolocationPermissionsHidePrompt() {
            super.onGeolocationPermissionsHidePrompt()
        }

        override fun onGeolocationPermissionsShowPrompt(
            origin: String?,
            callback: GeolocationPermissions.Callback?
        ) {
            callback?.invoke(origin, false, false)
        }

        private fun showChooser() {
            PictureSelector.create(this@ExcelActivity)
                .openGallery(SelectMimeType.ofImage())
                .setImageEngine(GlideEngine.createGlideEngine())
                .setSelectionMode(SelectModeConfig.SINGLE)
                .setPermissionsInterceptListener(object: OnPermissionsInterceptListener{
                    override fun requestPermission(
                        fragment: Fragment?,
                        permissionArray: Array<out String>?,
                        call: OnRequestPermissionListener?
                    ) {
                        if (permissionArray.isNullOrEmpty()) {
                            call?.onCall(permissionArray, true)
                            return
                        }
                        Log.d("lhp-image", "requestPermission: ${permissionArray!!.joinToString(",")}")
                        val message = permissionArray!!.map {
                            when (it) {
                                Permission.CAMERA -> "相机权限：用于拍照获取图片"
                                Permission.READ_MEDIA_IMAGES -> "访问图片权限：用于读取图片列表"
                                Permission.READ_MEDIA_VIDEO -> "访问视频权限：用于读取视频列表"
                                Permission.READ_MEDIA_AUDIO -> "访问音频权限：用于读取音频列表"
                                Permission.READ_EXTERNAL_STORAGE -> "外部存储权限：用于读取图片"
                                else -> it
                            }
                        }.joinToString("\n")
                        fragment!!.ensurePermission(
                            permissions = permissionArray.toList().toTypedArray(),
                            message = message ?: "",
                            onAllGranted = {
                                call?.onCall(permissionArray, true)
                            },
                            onDenied = {
                                call?.onCall(permissionArray, false)
                            }
                        )

                    }

                    override fun hasPermissions(
                        fragment: Fragment?,
                        permissionArray: Array<out String>?
                    ): Boolean {
                        return XXPermissions.isGranted(context, permissionArray)
                    }

                })
                .setCompressEngine(object: CompressFileEngine {
                    override fun onStartCompress(
                        context: Context?,
                        source: ArrayList<Uri>?,
                        call: OnKeyValueResultCallbackListener?
                    ) {
                        Luban.with(context)
                            .load(source)
                            .ignoreBy(100)
                            .setCompressListener(object : OnNewCompressListener {
                                override fun onStart() {

                                }

                                override fun onSuccess(source: String?, compressFile: File?) {
                                    call?.onCallback(source,compressFile?.absolutePath)
                                }

                                override fun onError(source: String?, e: Throwable?) {
                                    call?.onCallback(source,null)
                                }

                            })
                            .launch()
                    }

                })
                .forResult(object : OnResultCallbackListener<LocalMedia> {
                    override fun onResult(result: ArrayList<LocalMedia>?) {
                        result?.firstOrNull()?.compressPath?.let {
                            //val uri = UriUtils.file2Uri(File(it))
                            var uri: Uri = if (it.startsWith("/")) {
                                UriUtils.file2Uri(File(it))
                            } else Uri.parse(it)

                            chooseFileCallback?.onReceiveValue(arrayOf(uri))
                            chooseFileCallback = null

                        }
                    }

                    override fun onCancel() {
                        chooseFileCallback?.onReceiveValue(emptyArray())
                        chooseFileCallback = null
                    }

                })

//            PictureSelector.create(this@ExcelActivity)
//                .openGallery(SelectMimeType.ofImage())
//                .setImageEngine(GlideEngine.createGlideEngine())
//                .forResult(object : OnResultCallbackListener<LocalMedia?> {
//                    override fun onResult(result: ArrayList<LocalMedia?>?) {
//                        result?.firstOrNull()?.path?.let {
//                            val uri = UriUtils.file2Uri(File(it))
//                            chooseFileCallback?.onReceiveValue(arrayOf(uri))
//                            chooseFileCallback = null
//                        }
//                    }
//                    override fun onCancel() {}
//                })
        }


    }

    /**
     * webview没有选择文件也要传null，防止下次无法执行
     */
    fun clearUploadMessage() {
        chooseFileCallback?.onReceiveValue(null)
        chooseFileCallback = null

    }

    inner class GetHtmlAndDocxListener(val doc: ExcelBean) : RichEditorCallback.OnGetHtmlAndDocxListener {
        override fun getHtmlAndDocx(html: String?, docxBase64: String?) {
            //base64
            if (TextUtils.isEmpty(docxBase64) || TextUtils.isEmpty(html)) {
                ToastUtils.showShort(R.string.pls_type_your_content)
                return
            }
            LogUtils.d(html)
            LogUtils.d(docxBase64)
            var docx =
                docxBase64!!.replaceFirst(
                    "^data:application/vnd.openxmlformats-officedocument.spreadsheetml.sheet;base64,".toRegex(),
                    ""
                )
            val decode = Base64.decode(docx, Base64.CRLF)
            FileIOUtils.writeFileFromBytesByStream(doc.xlsxPath, decode)
            FileIOUtils.writeFileFromString(doc.path, html)
            ToastUtils.showShort(R.string.save_ok)
            if (shouldFinish){
                finish()
            }
        }

    }


}